package com.dlc.felear.xiaoensale.helper;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;

import com.dlc.felear.xiaoensale.constant.Constant;
import com.dlc.felear.xiaoensale.deviceControlSf.HotControl;
import com.dlc.felear.xiaoensale.dlc_serial_port.DlcSerialPortClient;
import com.dlc.felear.xiaoensale.entity.CmdInfo;
import com.dlc.felear.xiaoensale.factory.CmdList;
import com.dlc.felear.xiaoensale.utils.HexUtil;
import com.dlc.felear.xiaoensale.utils.RecordLog;

import org.simple.eventbus.EventBus;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class DeviceControlHelper implements Handler.Callback, IoInputHelper.IoInputCallback {
    private static final String TAG = "DeviceControlHelper";
    public static final int WHAT_DELAY = 1123;
    private static DeviceControlHelper deviceControlHelper;
    private ArrayBlockingQueue<byte[]> cmds = new ArrayBlockingQueue<>(300);
    private ScheduledExecutorService scheduledThreadPool;
    private IoInputHelper inputHelper;
    private IoOutHelper ioOutHelper;
    private int flag = 0;
    private Map<Byte, CmdInfo> cmdMaps;
    private String inputIoSerialName = Constant.INPUTIOSERIALNAME;
    private String outputIoSerialName = Constant.OUTPUTIOSERIALNAME;
    private Handler handler;
    private LiaoHeHelper liaoHeHelper;
    private JiaoBanHelper jiaoBanHelper;
    private YetiTiaoLiaoHelper yetiTiaoLiaoHelper;
    private GuotiHelper guotiHelper;
    private HotControl hotControl;
    private Context context;
    private int addr1 = 2;
    private int addr2 = 3;


    public static DeviceControlHelper getDeviceControlHelper(Context context) {
        if (deviceControlHelper == null) {
            synchronized (DeviceControlHelper.class) {
                if (deviceControlHelper == null) {
                    deviceControlHelper = new DeviceControlHelper(context);
                }
            }
        }
        return deviceControlHelper;
    }

    private DeviceControlHelper(Context context) {
        allStop();
        scheduledThreadPool = new ScheduledThreadPoolExecutor(8);
        cmdMaps = new HashMap<>();
        inputHelper = new IoInputHelper(this);
        ioOutHelper = new IoOutHelper();
        handler = new Handler(this);
        this.context = context;
        liaoHeHelper = new LiaoHeHelper(ioOutHelper, inputHelper, outputIoSerialName, scheduledThreadPool);
        jiaoBanHelper = new JiaoBanHelper(inputHelper);
        yetiTiaoLiaoHelper = new YetiTiaoLiaoHelper(scheduledThreadPool, ioOutHelper);
        guotiHelper = new GuotiHelper(context,ioOutHelper, inputHelper, outputIoSerialName,
                scheduledThreadPool, jiaoBanHelper, liaoHeHelper);
        jiaoBanHelper.setGuotiHelper(guotiHelper);
        liaoHeHelper.setGuotiHelper(guotiHelper);
        yetiTiaoLiaoHelper.setGuotiHelper(guotiHelper);
        hotControl= HotControl.getInstance(Constant.EVENT_RECEIVE_STEP_MOTOR);
        startLoop();
        loopTime();
    }

    /**
     * 轮训读取控制器的状态
     */
    public void loopTime() {
        Session session = Session.getSession();
        int function = session.getInt(Constant.DEVICE_FUNTION, 0);
        if (function != 0) {
            return;
        }
        scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                sendCmd(inputIoSerialName, CmdList.queryInputIoStatus(1));
                printMsg();
            }
        }, 4000, 80, TimeUnit.MILLISECONDS);

        scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                sendCmd(outputIoSerialName, CmdList.queryOuputIoStatus(addr1));
                sendCmd(outputIoSerialName, CmdList.queryOuputIoStatus(addr2));
                liaoHeHelper.looper();
                printMsg();
            }
        }, 4000, 500, TimeUnit.MILLISECONDS);
    }

    private void initConAdd() {
        controlOutputIo(tmp++, 255);
        sendCmd(outputIoSerialName, CmdList.setControlMoudelAdd(1, 3));
    }


    /**
     * 指令分发队列
     */
    private void startLoop() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    byte[] data = null;
                    while ((data = cmds.take()) != null) {
                        dispatcherCmd(data);
                        Thread.sleep(20);
                    }
                } catch (Exception e) {
                    startLoop();
                }

            }
        }).start();
    }


    /**
     * 指令分发
     *
     * @param data
     */
    public void dispatcherCmd(byte[] data) {
        inputHelper.setEnable();
        Log.e(TAG, "分发指令：" + HexUtil.bytes2HexString(data));
        switch (data[1]) {
            case (byte) 0x11:
                //搅拌
                jiaoBanHelper.paserData(data[3]);
                break;
            case (byte) 0x12:
                //洗锅
                guotiHelper.xiguoAction(data[3]);
                break;
            case (byte) 0x13:
                //倒菜、出锅
                guotiHelper.chuguo();
                break;
            case (byte) 0x14:
                //加食材
                liaoHeHelper.handleGz(data[3], (byte) 10);
                break;
            case (byte) 0x15:
                //抽风机
                guotiHelper.choufeng(data[3]);
                break;
            case (byte) 0x16:
                //固体调料
                guotiHelper.jiaguti(data[3], data[4] * 1000);
                break;
            case (byte) 0x17:
                //液体调料
                yetiTiaoLiaoHelper.paserData(data[3], data[4] * 1000);
                break;
            case (byte) 0x18:
                //抽风
                guotiHelper.choufeng(data[3]);
                break;
            case (byte) 0x19:
                //复位
                actionFw(data[3]);
                break;
            case (byte) 0x21:
                //加热
//                hotControl.setLevel(data[3],data[4]);
                break;

        }
    }

    private void actionFw(byte value) {
        if (value == 0) {
            //料盒复位
            liaoHeHelper.handleGz((byte) 5, (byte) 0);
        } else if (value == 1) {
            //锅体复位
            guotiHelper.gtFw();
        }
    }


    /**
     * 接收串口返回的数据
     *
     * @param cmd
     */
    public void recieveOutputResult(byte[] cmd) {
        Log.e(TAG, HexUtil.bytes2HexString(cmd));
        if (CmdList.checkDataComplete(cmd) && cmd.length > 5) {
            if ((cmd[0] == (byte) 0x03 || cmd[0] == (byte) 0x02)
                    && cmd[1] == (byte) 0x01 && cmd[2] == (byte) 0x04) {
                //IO输出采集状态
                ioOutHelper.ouputStatus(cmd);
            }
            addr1 = cmd[0];
            Log.e(TAG, "指令校验通过：" + HexUtil.bytes2HexString(cmd));
        } else {
            Log.e(TAG, "指令校验不通过：" + HexUtil.bytes2HexString(cmd));
        }
    }

    public void recieveInputResult(byte[] cmd) {
        Log.e(TAG, "input=" + HexUtil.bytes2HexString(cmd));
        if (CmdList.checkDataComplete(cmd) && cmd[0] == (byte) 0x01
                && cmd[1] == (byte) 0x02 && cmd[2] == (byte) 0x07) {
            inputHelper.inputStatus(cmd);
        } else {
            Log.e(TAG, "指令校验不通过：" + HexUtil.bytes2HexString(cmd));
        }
    }

    public void recieveJbResult(byte[] cmd) {
        Log.e(TAG, "recieveJbResult=" + HexUtil.bytes2HexString(cmd));
        if (CmdList.checkDataComplete(cmd)) {
            jiaoBanHelper.reviceData(cmd);
        }
    }

    /**
     * 缓存将要执行的指令
     *
     * @param cmd
     */
    public void recieveCmd(byte[] cmd) {
        if (CmdList.checkDataComplete(cmd) || (CmdList.checkSum16(cmd)
                && cmd[0] == (byte) 0xab && cmd[3] == (byte) 0x04)) {
            cmds.offer(cmd);
        }
    }

    byte tmp = 1;


    /**
     * io状态控制
     *
     * @param num
     * @param value
     */
    private void controlOutputIo(byte num, int value) {
        if (num >= 26) {
            sendCmd(outputIoSerialName, CmdList.controlOutputIo(addr2, num - 26, value));
        } else {
            sendCmd(outputIoSerialName, CmdList.controlOutputIo(addr1, num, value));
        }
    }

    public void recieveJb(byte[] data){
        jiaoBanHelper.reviceData(data);
    }

    private void sendCloseMsgToMsg(byte num, long delay) {
        Message message = new Message();
        message.what = WHAT_DELAY;
        message.arg1 = num;
        handler.sendMessageDelayed(message, delay);
    }


    private void printMsg() {
        EventBus.getDefault().post(inputHelper.getInputMaps(), Constant.ACTION_INPUT_IO_INFO_RESULT);
        EventBus.getDefault().post(ioOutHelper.getOutputMaps(), Constant.ACTION_OUTPUT_IO_INFO_RESULT);
    }


    private void sendCmd(String serialNo, byte[] data) {
//        Log.e(TAG, "cmd=" + HexUtil.bytes2HexString(data));
        DlcSerialPortClient.getInstance().send(serialNo, data);
    }


    @Override
    public boolean handleMessage(Message msg) {
        if (msg.what == WHAT_DELAY) {
            controlOutputIo((byte) msg.arg1, 0);
        }
        return false;
    }

    /**
     * 急停
     */
    private void allStop() {
        sendCmd(outputIoSerialName, CmdList.allOuputIoClose(addr1));
        sendCmd(outputIoSerialName, CmdList.allOuputIoClose(addr2));
    }

    public String getDeviceErrorMsg() {
        if (TextUtils.isEmpty(liaoHeHelper.devceiStatus())) {
            return liaoHeHelper.devceiStatus();
        }

        if (TextUtils.isEmpty(guotiHelper.getErrorMsg())) {
            return guotiHelper.getErrorMsg();
        }
        return "";
    }

    @Override
    public void ioInputResult(final byte index) {
//        log("触发传感器X" + index);
        scheduledThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                jiaoBanHelper.sensorStatus(index);
                liaoHeHelper.sensorStatus(index);
                liaoHeHelper.sensorStatus(index);
                guotiHelper.sensorStatus(index);
                yetiTiaoLiaoHelper.sensor(index);
            }
        });
    }

    private void log(String msg) {
        RecordLog.getInstance().saveLog(msg);
        Log.e(TAG, msg);
    }


    private void sendWarnMsg(int level, String msg) {
        Log.e(TAG, "告警等级=" + level + " msg=" + msg);
    }


    /**
     * 打开IO
     *
     * @param num
     */
    public void openOutPutIo(byte num) {
        switch (num) {
            case 0:
                //锅体转动
                openHuchiIO(num, (byte) 1);
                break;
            case 1:
                //锅体转动
                openHuchiIO(num, (byte) 0);
                break;
            case 2:
            case 3:
                //搅拌转动
//                jiaoBanHelper.rotateStepMotor(num);
                break;
            case 4:
                //料盒翻转
                openHuchiIO(num, (byte) 5);
                break;
            case 5:
                //料盒翻转
                openHuchiIO(num, (byte) 4);
                break;
            case 6:
                //料盒格子1
                openHuchiIO(num, (byte) 7);
                break;
            case 7:
                //料盒格子1
                openHuchiIO(num, (byte) 6);
                break;
            case 8:
                //料盒格子2
                openHuchiIO(num, (byte) 9);
                break;
            case 9:
                //料盒格子2
                openHuchiIO(num, (byte) 8);
                break;
            case 10:
                //料盒格子3
                openHuchiIO(num, (byte) 11);
                break;
            case 11:
                //料盒格子3
                openHuchiIO(num, (byte) 10);
                break;
            case 12:
                //料盒格子4
                openHuchiIO(num, (byte) 13);
                break;
            case 13:
                //料盒格子4
                openHuchiIO(num, (byte) 12);
                break;
            default:
                openIO(num);

        }

    }


    private void openHuchiIO(final byte num1, final byte num2) {
        scheduledThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    controlOutputIo(num2, 0);
                    Thread.sleep(200);
                    controlOutputIo(num1, 255);
                    sendCloseMsgToMsg(num1, 200);
                } catch (Exception e) {

                }
            }
        });
    }

    public void stopAction() {
        guotiHelper.choufeng((byte) 0);
        yetiTiaoLiaoHelper.closeAction();
        guotiHelper.closeAction();
        jiaoBanHelper.stopCmd();
    }

    private void openIO(final byte num) {
        log("Io num=" + num);
        scheduledThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                controlOutputIo(num, 255);
                sendCloseMsgToMsg(num, 200);
            }
        });
    }

}
